﻿using log4net;
using log4net.Config;
using log4net.Repository;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;

namespace Common
{
    public class LoggerHelper
    {

        /// <summary>
        ///  log4net 仓储库
        /// </summary>
        private static ILoggerRepository _repository;
        private static readonly ConcurrentDictionary<string, ILog> Loggers = new ConcurrentDictionary<string, ILog>();

        private static readonly object _lock = new object();
        static LoggerHelper()
        {
            _repository = LogManager.CreateRepository("NETCoreRepository");
            SetConfig(_repository, "log4net.config");
        }

        /// <summary>
        /// 读取配置文件，并使其生效。如果未找到配置文件，则抛出异常
        /// </summary>
        /// <param name="repository"></param>
        /// <param name="configFilePath">配置文件全路径</param>
        public static void SetConfig(ILoggerRepository repository, string configFilePath)
        {
            _repository = repository;
            var fileInfo = new FileInfo(configFilePath);
            if (!fileInfo.Exists)
            {
                throw new Exception("未找到配置文件" + configFilePath);
            }
            XmlConfigurator.ConfigureAndWatch(_repository, fileInfo);
        }


        /// <summary>
        /// 获取记录器
        /// </summary>
        /// <param name="source">soruce</param>
        /// <returns></returns>
        private static ILog GetLogger(string source)
        {
            if (Loggers.ContainsKey(source))
            {
                return Loggers[source];
            }
            else
            {
                ILog logger = LogManager.GetLogger(_repository.Name, source);
                Loggers.TryAdd(source, logger);
                return logger;
            }
        }
        #region Log a message object

        /// <summary>
        /// 调试信息日志
        /// </summary>
        /// <param name="msg">日志信息</param>
        public static void Debug(string msg)
        {
            ILog logger = GetLogger("Debug");
            if (logger.IsDebugEnabled)
            {
                var stackTrace = new StackTrace();
                var stackFrame = stackTrace.GetFrame(1);
                var methodBase = stackFrame.GetMethod();
                var message = "命名空间：" + methodBase.ReflectedType.FullName + ",方法名称：" + methodBase.Name + "\r\n日志内容：" + msg;
                logger.Info(message);
            }
        }
        /// <summary>
        /// 错误信息日志
        /// </summary>
        /// <param name="msg">日志信息</param>
        public static void Error(string msg)
        {
            ILog logger = GetLogger("Debug");
            if (logger.IsErrorEnabled)
            {
                var stackTrace = new StackTrace();
                var stackFrame = stackTrace.GetFrame(1);
                var methodBase = stackFrame.GetMethod();
                var message = "命名空间：" + methodBase.ReflectedType.FullName + ",方法名称：" + methodBase.Name + "\r\n日志内容：" + msg;
                logger.Info(message);
            }
        }
        /// <summary>
        /// 异常错误信息日志
        /// </summary>
        /// <param name="throwMsg">异常抛出信息</param>
        /// <param name="ex">异常信息</param>
        public static void Error(string throwMsg, Exception ex)
        {
            ILog logger = GetLogger("Error");
            if (logger.IsErrorEnabled)
            {

                var message =
                    $"抛出信息：{throwMsg} \r\n异常类型：{ex.GetType().Name} \r\n异常信息：{ex.Message} \r\n堆栈调用：\r\n{ex.StackTrace}";
                logger.Error(message);
            }
        }
        /// <summary>
        /// 异常错误信息
        /// </summary>
        /// <param name="source">source</param>
        /// <param name="throwMsg">异常抛出信息</param>
        /// <param name="ex">异常信息</param>
        public static void Error(Type source, object throwMsg, Exception ex)
        {
            ILog logger = GetLogger("Error");
            if (logger.IsErrorEnabled)
            {
                var message =
                    $"抛出信息：{throwMsg} \r\n异常类型：{ex.GetType().Name} \r\n异常信息：{ex.Message} \r\n【堆栈调用】：\r\n{ex.StackTrace}";
                logger.Error(message);
            }
        }
        /// <summary>
        /// 关键信息日志
        /// </summary>
        /// <param name="msg">日志信息</param>
        public static void Info(string msg)
        {
            ILog logger = GetLogger("Info");
            if (logger.IsInfoEnabled)
            {
                var stackTrace = new StackTrace();
                var stackFrame = stackTrace.GetFrame(1);
                var methodBase = stackFrame.GetMethod();
                var message = "命名空间："+methodBase.ReflectedType.FullName+",方法名称：" + methodBase.Name + "\r\n日志内容：" + msg;
                logger.Info(message);
            }
        }

        /// <summary>
        /// 警告信息日志
        /// </summary>
        /// <param name="msg">日志信息</param>
        public static void Warn(string msg)
        {
            ILog logger = GetLogger("Warn");
            if (logger.IsWarnEnabled)
            {
                var stackTrace = new StackTrace();
                var stackFrame = stackTrace.GetFrame(1);
                var methodBase = stackFrame.GetMethod();
                var message = "命名空间：" + methodBase.ReflectedType.FullName + ",方法名称：" + methodBase.Name + "\r\n日志内容：" + msg;
                logger.Info(message);
            }
        }
        /// <summary>
        /// 失败信息日志
        /// </summary>
        /// <param name="msg">日志信息</param>
        public static void Fatal(string msg)
        {
            ILog logger = GetLogger("Fatal");
            if (logger.IsFatalEnabled)
            {
                var stackTrace = new StackTrace();
                var stackFrame = stackTrace.GetFrame(1);
                var methodBase = stackFrame.GetMethod();
                var message = "命名空间：" + methodBase.ReflectedType.FullName + ",方法名称：" + methodBase.Name + "\r\n日志内容：" + msg;
                logger.Info(message);
            }
        }
        #endregion


        /// <summary>
        /// 创建一个日志文件记录日志
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="message"></param>
        /// <param name="isSendEmail"></param>
        public static void WriteLog(string fileName, string message)
        {
            lock (_lock)
            {
                if (string.IsNullOrEmpty(fileName))
                {
                    fileName = DateTime.UtcNow.ToString("yyyy-MM-dd");
                }
                Write(string.Format("Log\\{0}.log", fileName), message, fileName);
            }
        }
        /// <summary>
        /// 保存在默认路径下,以当前时间为文件名生成日志文件
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="e">异常信息</param>
        /// <param name="isSendEmail">是否发邮件通知</param>
        public static void WriteErrorLog(string fileName, Exception e)
        {
            lock (_lock)
            {
                if (e != null)
                {
                    WriteError(string.Format("Log\\{0}.log", fileName), e, fileName);
                }
            }
        }

        private static void Write(string filePath, string message, string fileName)
        {
            ThreadPool.QueueUserWorkItem(delegate (object x)
            {
                try
                {
                    StringBuilder stringBuilder = new StringBuilder();
                    lock (_lock)
                    {
                        DirectoryInfo parent = Directory.GetParent(filePath);
                        DateTime dateTime;
                        if (parent.Exists)
                        {
                            //if (File.Exists(filePath))
                            //{
                            //    FileInfo fileInfo = new FileInfo(filePath);
                            //    if (fileInfo.Length >0)
                            //    {
                            //        int num = filePath.LastIndexOf(".log");
                            //        FileInfo obj = fileInfo;
                            //        string arg = filePath.Substring(0, num);
                            //        dateTime = DateTime.UtcNow;
                            //        obj.MoveTo(string.Format("{0}_{1}{2}", arg, dateTime.ToString("yyyy.MM.dd.HHmmss"), filePath.Substring(num, 4)));
                            //    }
                            //}
                        }
                        else
                        {
                            Directory.CreateDirectory(parent.FullName);
                        }
                        StringBuilder obj2 = stringBuilder;
                        dateTime = (DateTime)x;
                        obj2.AppendFormat("\r\n<br/>时间:{0}\r\n<br/>", DateTime.Now.ToString("yyyy-MM-dd  HH:mm:ss"));
                        stringBuilder.AppendFormat("文件:{0}\r\n\r\n<br/><br/>", filePath);
                        stringBuilder.AppendFormat("内容：{0}", message);
                        stringBuilder.Append("\r\n\r\n<br/><br/>--------------------Info-------------------------\r\n\r\n<br/>");
                        using (FileStream stream = new FileStream(filePath, FileMode.Append))
                        {
                            using (StreamWriter streamWriter = new StreamWriter(stream))
                            {
                                streamWriter.WriteLine(stringBuilder.ToString().Replace("<br/>", ""));
                                streamWriter.Flush();
                                streamWriter.Close();
                                streamWriter.Dispose();
                            }
                        }
                    }
                   
                }
                catch
                {
                }
            }, DateTime.UtcNow);
        }

        private static void WriteError(string filePath, Exception e, string fileName)
        {
            ThreadPool.QueueUserWorkItem(delegate (object x)
            {
                try
                {
                    StringBuilder stringBuilder = new StringBuilder();
                    lock (_lock)
                    {
                        DirectoryInfo parent = Directory.GetParent(filePath);
                        DateTime dateTime;
                        if (parent.Exists)
                        {
                            //if (File.Exists(filePath))
                            //{
                            //    FileInfo fileInfo = new FileInfo(filePath);
                            //    if (fileInfo.Length > 0)
                            //    {
                            //        int num = filePath.LastIndexOf(".log");
                            //        FileInfo obj = fileInfo;
                            //        string arg = filePath.Substring(0, num);
                            //        dateTime = DateTime.UtcNow;
                            //        obj.MoveTo(string.Format("{0}_{1}{2}", arg, dateTime.ToString("yyyy.MM.dd.HHmmss"), filePath.Substring(num, 4)));
                            //    }
                            //}
                        }
                        else
                        {
                            Directory.CreateDirectory(parent.FullName);
                        }
                        StringBuilder obj2 = stringBuilder;
                        dateTime = (DateTime)x;
                        obj2.AppendFormat("\r\n<br/>错误时间:{0}\r\n<br/>", DateTime.Now.ToString("yyyy-MM-dd  HH:mm:ss"));
                        stringBuilder.AppendFormat("日志文件:{0}\r\n\r\n<br/><br/>", filePath);
                        stringBuilder.AppendFormat("错误对象:{0}\r\n<br/>", e.Source);
                        stringBuilder.AppendFormat("异常方法:{0}\r\n<br/>", e.TargetSite.ToString());
                        stringBuilder.AppendFormat("错误信息：{0}\r\n<br/>", e.Message);
                        stringBuilder.AppendFormat("堆栈内容：{0}\r\n<br/>", e.StackTrace);
                        stringBuilder.Append("\r\n\r\n<br/><br/>--------------------Error-------------------------\r\n\r\n<br/>");
                        using (FileStream stream = new FileStream(filePath, FileMode.Append))
                        {
                            using (StreamWriter streamWriter = new StreamWriter(stream))
                            {
                                streamWriter.WriteLine(stringBuilder.ToString().Replace("<br/>", ""));
                                streamWriter.Flush();
                                streamWriter.Close();
                                streamWriter.Dispose();
                            }
                        }
                    }
                }
                catch
                {
                }
            }, DateTime.UtcNow);
        }
    }
}

